/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the GLQuake source code.

 The GLQuake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The GLQuake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the GLQuake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// physics_player.h - player movement physics
//


#ifndef __PHYSICS_PLAYER_H__
#define __PHYSICS_PLAYER_H__


/*
 ==============================================================================

 Player physics:

 Simulates the motion of a player through the environment. Input from the
 player is used to allow a certain degree of control over the motion.

 Used for local prediction on the client and true movement on the server.

 ==============================================================================
*/

enum pmType_t {
	PM_NORMAL,									// Normal movement
	PM_DEAD,									// No acceleration or turning, but free falling
	PM_NOCLIP,									// Flying without gravity nor collisions
	PM_SPECTATOR,								// Flying without gravity but with collisions
	PM_FREEZE									// Stuck in place without control
};

enum pmFlags_t {	
	PMF_SLIDING				= BIT(0),			// Player is sliding	
	PMF_JUMP_HELD			= BIT(1),			// Jump button is held down
	PMF_TIME_LAND			= BIT(2),			// pmTime is time before jump
	PMF_TIME_KNOCKBACK		= BIT(3),			// pmTime is an air-accelerate only time
	PMF_TIME_MANTLE			= BIT(4),			// pmTime is a mantle time
	PMF_TIME_WATERJUMP		= BIT(5),			// pmTime is a water jump time
	PMF_ALL_FLAGS			= (PMF_SLIDING | PMF_JUMP_HELD),
	PMF_ALL_TIMES			= (PMF_TIME_LAND | PMF_TIME_KNOCKBACK | PMF_TIME_MANTLE | PMF_TIME_WATERJUMP)
};

enum waterLevel_t {
	WATERLEVEL_NONE,
	WATERLEVEL_FEET,
	WATERLEVEL_KNEES,
	WATERLEVEL_WAIST,
	WATERLEVEL_SHOULDERS,
	WATERLEVEL_HEAD
};

class etPhysicsPlayer {
private:
	int						frameMsec;
	float					frameTime;

	glqVec3					viewForward;
	glqVec3					viewRight;

	float					playerSpeed;
	glqBounds				playerBounds;

	bool					walking;
	bool					groundPlane;
	trace_t					groundTrace;

public:
	// Player state (in / out)
	playerState_t *			state;

	// Parameters (in)
	bool					debug;

	float					gravity;

	userCmd_t				userCmd;

	// Results (out)
	int						waterType;
	waterLevel_t			waterLevel;

	// Callback functions

private:
	void					AddEvent (int eventType, int eventParm);

	void					Friction ();
	void					Accelerate (const glqVec3 &wishDir, float wishSpeed, float accel);

	float					UserCmdScale () const;

	void					UpdateViewAngles ();

	void					SetWaterLevel ();
	void					SetMoveSpeed ();

	void					DropTimers ();

	void					CheckStance ();
	void					CheckGround ();
	bool					CheckJump ();
	bool					CheckWaterJump ();

	bool					SlideMove (bool addGravity);
	void					StepSlideMove (bool addGravity);
	void					NoClipMove ();
	void					SpectatorMove ();
	void					WaterJumpMove ();
	void					WaterMove ();
	void					AirMove ();
	void					WalkMove ();

	void					MoveSingle (int msec);

public:
	void					MovePlayer ();
};


#endif	// __PHYSICS_PLAYER_H__